/*
 * Model class of MonteCarloApplication - multi threaded
 */
package javaapplication6.MODEL.MULTI;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import javaapplication6.MODEL.AbstractMonteCarloSimulation;

/**
 *
 * @author mathieubakrim
 */
public class MonteCarloSimulationMulti extends AbstractMonteCarloSimulation{
    /**
     * Simulation method
     * @param callPutFlag
     * @param s: share price of the day
     * @param x: strike price
     * @param t: Remaining time to option maturity
     * @param r: interest without risk
     * @param b: Carry rate cost of the option 
     * @param v: volatility
     * @param nSteps: number of intermediate points to calculate
     * @param nSimulations: number of way to explore
     * @return computed value of MonteCarlo, as an estimated price of the option
     * @throws java.lang.InterruptedException
     * @throws java.util.concurrent.ExecutionException
     */
    @Override
    public double MonteCarloStandardOption(String callPutFlag, final double s, double x,
            double t, double r, double b,double v, final int nSteps, int nSimulations) throws InterruptedException, ExecutionException{
        
        List<Callable<Double>> partitions = new ArrayList<Callable<Double>>();
        
        start = System.currentTimeMillis();        
                
        dt = t / nSteps;
        drift = (b - v * v / 2) * dt;
        vSqrt = v * Math.sqrt(dt);
        
        if("c".equals(callPutFlag)){    // It is a call
            z = 1;
        }            
        else if("p".equals(callPutFlag)){   // It is a put
            z = -1;
        }

        for (i = 1; i <= nSimulations; i++){
            partitions.add(new OneSimulation(st, nSteps, drift, vSqrt, s));
        }

        ExecutorService executorPool = Executors.newFixedThreadPool(poolSize);    
        List<Future<Double>> valueOfSimulation = executorPool.invokeAll(
        partitions, 10000, TimeUnit.SECONDS);
        executorPool.shutdown();    

        for(Future<Double> valueOfASimulation : valueOfSimulation){
            sum += Math.max(z *(valueOfASimulation.get() -x), 0);
        }
        res = Math.exp(-r * t)*(sum/nSimulations);
        
        end = System.currentTimeMillis();
        
        System.out.println("Number of Cores available is " + numberOfCores);
        System.out.println("Pool size is " + poolSize);
        System.out.println("Temps total: " + (end - start) + "ms");
        System.out.println("res :" + res);
        return res;
    }
}
